package com.fubowen.lepton.ui.reader.book.impl

import com.fubowen.lepton.bean.BookChapterBean
import com.fubowen.lepton.extension.agent
import com.fubowen.lepton.extension.trimChar
import com.fubowen.lepton.extension.tryGetDocument
import com.fubowen.lepton.ui.reader.book.IBook
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.jsoup.Jsoup
import org.jsoup.nodes.Document

class WebBook(
    override var url: String,
    override var onCompleted: IBook.() -> Unit = {}
) : IBook {
    override var isGetCatalogState = false
    override val chapterList = mutableListOf<BookChapterBean>()
    override var name: String = "未解析"
    override var errMsg: String? = null
    override var onProgressChanged: (BookChapterBean) -> Unit = {}

    private val tryCount: Int = 3
    private val timeout: Int = 30000
    private var isCatalogOfInitUrl = false
    private var document: Document? = null
    private val chapterRegex = "第\\s*[一二三四五六七八九十零\\d]+\\s*章"
    var onDownloadProgressChanged: (Int) -> Unit = {}
    var onDownloadCompleted: () -> Unit = {}
    var isDownloadChapter = false

    override fun tryGet() {
        val that = this
        CoroutineScope(Dispatchers.IO).launch {
            url.tryGetDocument(tryCount, timeout) { state, doc, err ->
                document = doc
                errMsg = err
                if (state) {
                    tryGetCatalog()
                }
                if (isGetCatalogState && isDownloadChapter) {
                    downloadChapter()
                }
                onCompleted(that)
            }
        }
    }

    override fun tryGetCatalog() {
        if (tryGetChapterList()) {
            isGetCatalogState = true
            tryGetName()
            tryGetUrl()
            isCatalogOfInitUrl = true
        } else {
            document?.let {
                val regex = "目录|章节列表|返回目录"
                val nodes = it.select("a:matches($regex)").distinct()
                for (item in nodes) {
                    val href = item.attr("href")
                    val absoluteUrl = java.net.URL(java.net.URL(item.baseUri()), href)
                    val url = absoluteUrl.toExternalForm()
                    document = Jsoup.connect(url).timeout(timeout).userAgent(agent).get()
                    if (tryGetChapterList()) {
                        isGetCatalogState = true
                        tryGetName()
                        tryGetUrl()
                        break
                    }
                }
            }
        }
    }

    override fun tryGetName() {
        document?.let {
            var meta = it.select("meta[property*=book_name]")
            if (meta != null) {
                name = meta.attr("content")
                return
            }
            meta = it.select("meta[property*=title]")
            if (meta != null) {
                name = meta.attr("content")
            }
        }
    }

    override fun tryGetUrl() {
        url = document?.baseUri() ?: ""
    }

    private fun tryGetChapterList(): Boolean {
        return document?.let {
            val nodeList = it.select("a:matches($chapterRegex)").distinct()
            val regex = Regex("第\\s*[一二三四五六七八九十零\\d]+\\s*章(.*)$")
            for (i in nodeList.indices) {
                val item = nodeList[i]
                val matchResult = regex.find(item.text())
                val href = item.attr("href")
                val absoluteUrl = java.net.URL(java.net.URL(item.baseUri()), href)
                val url = absoluteUrl.toExternalForm()
                if (matchResult != null) {
                    val bean = BookChapterBean(
                        name = matchResult.groupValues[1].trimChar() ?: "",
                        order = i + 1,
                        url = url,
                        isDownload = false
                    )
                    chapterList.add(bean)
                }
            }
            nodeList.isNotEmpty()
        } ?: false
    }

    private fun downloadChapter() {
        CoroutineScope(Dispatchers.IO).launch {
            for ((index, item) in chapterList.withIndex()) {
                getChapterContent(item.url) {
                    item.isDownload = true
                    item.content = it
                    item.words = it.length
                    onDownloadProgressChanged(index)
                }
                if (index == chapterList.size - 1) {
                    onDownloadCompleted()
                }
            }
        }
    }

    companion object {
        @JvmStatic
        fun getChapterContent(url: String?, callback: (String) -> Unit) {
            url.tryGetDocument { state, doc, _ ->
                if (state && doc != null) {
                    val node = doc.selectFirst(":has(>br:gt(10))")
                    if (node != null) {
                        node.text()
                        val content = node.wholeText().replace("\r", "\n")
                        callback(content)
                    }
                }
            }
        }
    }
}